#include "s_ipus_64Mb.h"

#include <stdio.h>
#include <string.h>

#define S_IPUS_64MBit_READ_CMD                          0x03
#define S_IPUS_64MBit_FAST_READ_CMD                     0x0B
#define S_IPUS_64MBit_FAST_READ_QUAD_CMD                0xEB
#define S_IPUS_64MBit_WRITE_CMD                         0x02
#define S_IPUS_64MBit_QUAD_WRITE_CMD                    0x38
#define S_IPUS_64MBit_ENTER_QUAD_MODE_CMD               0x35
#define S_IPUS_64MBit_EXIT_QUAD_MODE_CMD                0xF5
#define S_IPUS_64MBit_RESET_ENABLE_CMD                  0x66
#define S_IPUS_64MBit_RESET_CMD                         0x99
#define S_IPUS_64MBit_READID_CMD                        0x9F



static s_ipus_64Mb_state s_ipus_64Mb_check(s_ipus_64Mb_t *ipus_t)
{
    if(ipus_t == NULL)
    {
        return s_ipus_64Mb_struct_null;
    }
    if(ipus_t->spi_cs_enable == NULL)
    {
        return s_ipus_64Mb_cs_enable_null;
    }
    if(ipus_t->spi_cs_disable == NULL)
    {
        return s_ipus_64Mb_cs_disable_null;
    }
    if(ipus_t->spi_write == NULL)
    {
        return s_ipus_64Mb_write_null;
    }
    if(ipus_t->spi_read == NULL)
    {
        return s_ipus_64Mb_read_null;
    }
    if(ipus_t->delay_us == NULL)
    {
        return s_ipus_64Mb_delay_us_null;
    }
    return s_ipus_64Mb_ok;
}

s_ipus_64Mb_state s_ipus_64Mb_reset(s_ipus_64Mb_t *ipus_t)
{
    unsigned char reset[2] = {S_IPUS_64MBit_RESET_ENABLE_CMD, S_IPUS_64MBit_RESET_CMD};
    if(s_ipus_64Mb_check(ipus_t) != s_ipus_64Mb_ok)
    {
        return s_ipus_64Mb_check(ipus_t);
    }

    ipus_t->spi_cs_enable();
    ipus_t->spi_write(&reset[0], 1);
    ipus_t->spi_write(&reset[1], 1);
    ipus_t->delay_us(1000);
    ipus_t->spi_cs_disable();
    ipus_t->delay_us(1000);

    return s_ipus_64Mb_ok;
}

s_ipus_64Mb_state s_ipus_64Mb_readID(s_ipus_64Mb_t *ipus_t, unsigned short *ids)
{
    unsigned char data[4] = {S_IPUS_64MBit_READID_CMD, 0x00, 0x00, 0x00};
    unsigned char rdata[2] = {0x00, 0x00};
    if(s_ipus_64Mb_check(ipus_t) != s_ipus_64Mb_ok)
    {
        return s_ipus_64Mb_check(ipus_t);
    }
    ipus_t->spi_cs_enable();
    ipus_t->spi_write(&data[0], 4);
    ipus_t->spi_read(&rdata[0], 2);
    ipus_t->spi_cs_disable();

    *ids = rdata[0] << 8 | rdata[1];

    printf("0x%02x, 0x%02x\r\n", data[0], data[1]);

    return s_ipus_64Mb_ok;
}

s_ipus_64Mb_state s_ipus_64Mb_read(s_ipus_64Mb_t *ipus_t, unsigned int address, unsigned char *data, unsigned short len)
{
    unsigned char cmd[4] = {S_IPUS_64MBit_READ_CMD, \
                             (unsigned char)((address >> 16) & 0xFF), \
                             (unsigned char)((address >> 8) & 0xFF), \
                             (unsigned char)(address & 0xFF)};

    if(s_ipus_64Mb_check(ipus_t) != s_ipus_64Mb_ok)
    {
        return s_ipus_64Mb_check(ipus_t);
    }

    ipus_t->spi_cs_enable();
    ipus_t->spi_write(&cmd[0], 4);
    ipus_t->spi_read(data, len);
    ipus_t->spi_cs_disable();

    return s_ipus_64Mb_ok;
}

s_ipus_64Mb_state s_ipus_64Mb_write(s_ipus_64Mb_t *ipus_t, unsigned int address, const unsigned char *data, unsigned short len)
{
    unsigned char cmd[4] = {S_IPUS_64MBit_WRITE_CMD, \
                             (unsigned char)((address >> 16) & 0xFF), \
                             (unsigned char)((address >> 8) & 0xFF), \
                             (unsigned char)(address & 0xFF)};

    if(s_ipus_64Mb_check(ipus_t) != s_ipus_64Mb_ok)
    {
        return s_ipus_64Mb_check(ipus_t);
    }

    ipus_t->spi_cs_enable();
    ipus_t->spi_write(&cmd[0], 4);
    ipus_t->spi_write((unsigned char *)data, len);
    ipus_t->spi_cs_disable();

    return s_ipus_64Mb_ok;
}